#include <stdlib.h>
#include <assert.h>
#include <curses.h>
#include "game.h"
#include "ball.h"
#include "player.h"


void init_ball(BALL* b, int x, int y, char dir, int value) {
	b -> position.x = x;
	b -> position.y = y;
	b -> old_position.x = x;
	b -> old_position.y = y;
	b -> direction = dir;
	b -> value = value;
	b -> color = value + 2;
	b -> move_tick = 0;
}


//MOVEMENT STUFF

int is_ball_passable(FIELD* f, POINT* p) {
	//TODO: take obstacles into account
	return p -> x > 0 &&
		p -> x < f -> width - 1 &&
		p -> y > 0 &&
		p -> y < f -> height - 1;
}

void add_to_point(POINT* p1, POINT* p2) {
	p1 -> x = p1 -> x + p2 -> x;
	p1 -> y = p1 -> y + p2 -> y;
}

void direction_to_point(POINT* p, char dir) {
	if(dir & 0x0010) {
		p -> x = 1;
	} else {
		p -> x = -1;
	}
	if(dir & 0x0001) {
		p -> y = 1;
	} else {
		p -> y = -1;
	}
}
char point_to_direction(POINT* p) {
	assert((p -> x == 1 || p -> x == -1) && (p -> y == 1 || p -> y == -1));
	char dir = 0;
	dir = dir | (p -> x == 1 ? 0x10 : 0);
	dir = dir | (p -> y == 1 ? 0x1 : 0);
	return dir;
}

void bounce(BALL* b, FIELD* f) {
	POINT* pos = &(b -> position);
	POINT dir;
	
	//check if y is obstructed
	direction_to_point(&dir, b -> direction);
	dir.x = 0;
	add_to_point(&dir, pos);
	int invertY = !is_ball_passable(f, &dir);
	
	//check if x is obstructed
	direction_to_point(&dir, b -> direction);
	dir.y = 0;
	add_to_point(&dir, pos);
	int invertX = !is_ball_passable(f, &dir);
	
	//invert direction away from obstruction
	direction_to_point(&dir, b -> direction);
	dir.x = invertX ? -dir.x : dir.x;
	dir.y = invertY ? -dir.y : dir.y;
	b -> direction = point_to_direction(&dir);
}

void move_ball(FIELD* f, int i) {
	BALL* b = f -> balls[i];
	POINT* pos = &b -> position;
	POINT direction_vector;
	direction_to_point(&direction_vector, b -> direction);
	add_to_point(&direction_vector, pos); 

	b -> old_position.x = b -> position.x;
	b -> old_position.y = b -> position.y;
	
	bounce(b, f);
	
	if (is_ball_passable(f, &direction_vector)) {
		b -> position = direction_vector;
	} else {
		
		direction_to_point(&direction_vector, b -> direction);
		add_to_point(&direction_vector, pos);
		b -> position = direction_vector;
	}
	if (is_on_player(f -> player, &b -> position)) {
		if (f -> player -> body[f -> player -> head_ptr] -> x == pos -> x &&
			f -> player -> body[f -> player -> head_ptr] -> y == pos -> y) {
			
			eat_ball(f, i);
		} else {
			set_lost(f -> state);
		}
	}
}

void move_balls(FIELD* f) {
	for (int i = 0; i < f -> ball_count; i++) {
		BALL* b = f -> balls[i];
		b -> move_tick += (b -> value * b -> value);
		if (b -> move_tick > 15) {
			b -> move_tick = 0;
			move_ball(f, i);
		}
	}
}
